2090-半径为 k 的子数组平均值

Raphael Liu Lv10

给你一个下标从 0 开始的数组 nums ,数组中有 n 个整数,另给你一个整数 k

半径为 k 的子数组平均值 是指:nums 中一个以下标 i中心半径k
的子数组中所有元素的平均值,即下标在 i - ki + k 范围( i - ki + k)内所有元素的平均值。如果在下标 i 前或后不足 k 个元素,那么 半径为 k 的子数组平均值-1

构建并返回一个长度为 n 的数组 __avgs __ ,其中 __avgs[i] __ 是以下标 i 为中心的子数组的 半径为 k
的子数组平均值

x 个元素的 平均值x 个元素相加之和除以 x ,此时使用截断式 整数除法 ,即需要去掉结果的小数部分。

  • 例如,四个元素 2315 的平均值是 (2 + 3 + 1 + 5) / 4 = 11 / 4 = 2.75,截断后得到 2

示例 1:

**输入:** nums = [7,4,3,9,1,8,5,2,6], k = 3
**输出:** [-1,-1,-1,5,4,4,-1,-1,-1]
**解释:**
- avg[0]、avg[1] 和 avg[2] 是 -1 ,因为在这几个下标前的元素数量都不足 k 个。
- 中心为下标 3 且半径为 3 的子数组的元素总和是:7 + 4 + 3 + 9 + 1 + 8 + 5 = 37 。
  使用截断式 **整数除法** ,avg[3] = 37 / 7 = 5 。
- 中心为下标 4 的子数组,avg[4] = (4 + 3 + 9 + 1 + 8 + 5 + 2) / 7 = 4 。
- 中心为下标 5 的子数组,avg[5] = (3 + 9 + 1 + 8 + 5 + 2 + 6) / 7 = 4 。
- avg[6]、avg[7] 和 avg[8] 是 -1 ,因为在这几个下标后的元素数量都不足 k 个。

示例 2:

**输入:** nums = [100000], k = 0
**输出:** [100000]
**解释:**
- 中心为下标 0 且半径 0 的子数组的元素总和是:100000 。
  avg[0] = 100000 / 1 = 100000 。

示例 3:

**输入:** nums = [8], k = 100000
**输出:** [-1]
**解释:**
- avg[0] 是 -1 ,因为在下标 0 前后的元素数量均不足 k 。

提示:

  • n == nums.length
  • 1 <= n <= 105
  • 0 <= nums[i], k <= 105

方法一:一次遍历

思路与算法

根据题目描述,只有当中心位置 i \in [k, n-k-1] 时,整个长度为 2k+1 的子区间才会完整地落在数组 nums 内部。当 i < k 或者 i \geq n-k 时,对应的平均值为 -1。

因此如果 k \geq n-k-1 即 2k+1 \geq n,答案数组中所有的元素均为 -1。否则,我们首先计算出数组 nums 的前 2k+1 个元素的和,放在答案数组的 ans}[k] 中。由于:

\left{
\begin{aligned}
& \textit{ans}[i - 1] && = \textit{nums}[i - k - 1] + \textit{nums}[i - k] + \cdots + \textit{nums}[i + k - 1] \
& \textit{ans}[i] && = \textit{nums}[i - k] + \cdots + \textit{nums}[i + k - 1] + \textit{nums}[i + k]
\end{aligned}
\right.

因此随后只需要通过递推式:

\textit{ans}[i] = \textit{ans}[i - 1] + \textit{nums}[i + k] - \textit{nums}[i - k - 1]

即可得到所有中心位置 i \in [k, n-k-1] 且长度为 2k+1 的子数组的和。最后将每一个和除以 2k+1 即可得到平均数。

代码

[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
vector<int> getAverages(vector<int>& nums, int k) {
int n = nums.size();
vector<int> ans(n, -1);
if (k * 2 + 1 <= n) {
long long sum = accumulate(nums.begin(), nums.begin() + k * 2 + 1, 0LL);
for (int i = k; i + k < n; ++i) {
if (i != k) {
sum += nums[i + k] - nums[i - k - 1];
}
ans[i] = sum / (k * 2 + 1);
}
}
return ans;
}
};
[sol1-Python3]
1
2
3
4
5
6
7
8
9
10
11
class Solution:
def getAverages(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
ans = [-1] * n
if k * 2 + 1 <= n:
total = sum(nums[:k * 2 + 1])
for i in range(k, n - k):
if i != k:
total += nums[i + k] - nums[i - k - 1]
ans[i] = total // (k * 2 + 1)
return ans

复杂度分析

  • 时间复杂度:O(n)。

  • 空间复杂度:O(1),这里不计算返回值数组 ans 需要的空间。

 Comments
On this page
2090-半径为 k 的子数组平均值